package com.ziytek.web.citizen.service;

import com.google.gson.Gson;
import com.ziytek.web.citizen.caffeine.CachePutOrGet;
import com.ziytek.web.citizen.config.caffeine.CaffeineUtil;
import com.ziytek.web.citizen.constant.*;
import com.ziytek.web.citizen.enums.ErrorTypeEnum;
import com.ziytek.web.citizen.enums.StepTypeNoEnum;
import com.ziytek.web.citizen.mapper.OperationDetailMapper;
import com.ziytek.web.citizen.mapper.TableMapper;
import com.ziytek.web.citizen.model.bean.CapStatsVo;
import com.ziytek.web.citizen.model.bean.JobTimes;
import com.ziytek.web.citizen.model.data.BatteryDetail;
import com.ziytek.web.citizen.model.data.OneBattery;
import com.ziytek.web.citizen.model.data.RealData;
import com.ziytek.web.citizen.model.rsp.R;
import com.ziytek.web.citizen.model.vo.OperationVo;
import com.ziytek.web.citizen.model.vo.RealTimeVo;
import com.ziytek.web.citizen.model.vo.StatsDo;
import com.ziytek.web.citizen.quartz.QuartzService;
import com.ziytek.web.citizen.quartz.execute.StepIssuedEventListenerQuartzJob;
import com.ziytek.web.citizen.util.BatteryCapacityCalculator;
import com.ziytek.web.citizen.util.KeyUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.List;

/**
 * @author fengh
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class RealDataProService {

    private final Gson gson;
    private final TableMapper tableMapper;
    private final DoorsService doorsService;
    private final CachePutOrGet cachePutOrGet;
    private final OneBatteryService oneBatteryService;
    private final QuartzService quartzService;
    private final CompressionService compressionService;
    private final BoardAbnormalService boardAbnormalService;
    private final OperationDetailMapper operationDetailMapper;
    private final OperationVoCacheService operationVoCacheService;
    private final StepIssuedEventListenerQuartzJob stepIssuedEventListenerQuartzJob;

    public void process(Object msg) {
        if (!(msg instanceof RealData realData)) {
            return;
        }

        Assert.notNull(realData.getD(), "realData.d is null");

        // 删除原始数据
        //realData.setBd(null);
        // 解析处理周期数据
        setOrUpdateCache(realData);
    }

    protected void setOrUpdateCache(RealData rd) {
        var boardNoList = doorsService.getBoardNoList();
        var thread = Thread.startVirtualThread(() -> rd.getD().forEach(b -> b.getD().forEach(o -> oneBatteryProcess(rd, b, o, boardNoList))));

        try {
            thread.join();
        } catch (InterruptedException e) {
            log.error("channelRead:{}", e.getMessage());
        }
    }

    /**
     * 处理单个电池通道数据
     *
     * @param rd          数据
     * @param b           电池通道数据
     * @param o           电池通道数据
     * @param boardNoList 电池通道数据
     */
    private void oneBatteryProcess(RealData rd, BatteryDetail b, OneBattery o, List<Integer> boardNoList) {
        // 取绝对值
        o.setC(Math.abs(o.getC()));
        o.setV(Math.abs(o.getV()));

        // 判断电池电芯电压及电流是否全部为0,是则为空闲电池,一块恒流板8个通道电池电压及电流全为0则认为是通讯异常
        boardAbnormalService.boardAbnormal(rd.getB(), b.getC(), o.getP(), o.getC(), o.getV());

        // 不需要处理的分控板电池通道
        if (b.getC() == null || !boardNoList.contains(b.getC())) {
            //log.info("不处理分控板电池通道:{},boardNo:{}-{}", b.getC(), boardNoList.contains(b.getC()), gson.toJson(boardNoList));
            return;
        }

        var key = rd.getB() + CaffeineUtil.CACHE_KEY_SYMBOL + b.getC() + CaffeineUtil.CACHE_KEY_SYMBOL + o.getP();
        // 每个电池通道的工步操作缓存
        var opKey = KeyUtil.commandOperateKey(rd.getB(), b.getC(), o.getP());
        var vo = operationVoCacheService.getOperationVo(opKey);

        // todo 操作记录缓存数据不存在, 查询数据库，确保不是停电等原因造成的终止或重启导致缓存清除
        // 工步未执行，不处理数据
        if (null == vo || SettingConstant.SHELVE.equalsIgnoreCase(vo.getSetType()) || ServerConstant.START_FLAG_DISABLE == vo.getStartFlag()) {
            boolean isShelve = null != vo && SettingConstant.SHELVE.equalsIgnoreCase(vo.getSetType());
            double time = null != vo && null != vo.getExpectedTime() ? vo.getExpectedTime() * NumConstant.DOUBLE_SIXTY : Double.MAX_VALUE;
            CapStatsVo svo = checkPutCache(key, o.getC(), o.getV(), isShelve, time);

            // todo 转换更新 首页长连接数据缓存
            oneBatteryCache(vo, svo, rd.getB(), b.getC(), o.getP());
            oneBatteryService.oneBratty(rd.getB(), b.getC(), o.getP(), svo);
            return;
        }

        // 完成更新时间电流电压
        if (ServerConstant.START_FLAG_FINISH == vo.getStartFlag() && cachePutOrGet.getStatsCache(key) instanceof CapStatsVo oldStats) {
            oldStats.setIv(o.getC(), o.getV());
            cachePutOrGet.putStatsCache(key, oldStats);
            return;
        }

        // 充电获取截止电流，放电获取截止电压
        var cutOff = null == vo.getCutOff() ? NumConstant.INT_ZERO : vo.getCutOff();
        // 充电、放电计算电池容量
        chargeOrDischargePutCache(opKey, vo, o, key, o.getC(), o.getV(), cutOff, vo.getSetType());

        // todo 转换更新 首页长连接数据缓存
        var svo = cachePutOrGet.getStatsCache(key);
        oneBatteryCache(vo, svo, rd.getB(), b.getC(), o.getP());

        oneBatteryService.oneBratty(rd.getB(), b.getC(), o.getP(), svo);
        //var d = oneBatteryService.oneBrattyRealData(rd.getB() + "", ServerConstant.DOOR_FRONT_LEFT);
        //log.info("测试oneBatteryService:{}", gson.toJson(d));
    }


    protected void chargeOrDischargePutCache(String opKey, OperationVo vo, OneBattery o, String key, int current, int voltage, int cutOff, String commandSetType) {
        var linkedList = cachePutOrGet.getCurrentCache(key);

        // 指令下发前60秒内数据处理
        var firstDataCount = getFirstDataCount(vo, key);

        if (linkedList == null) {
            linkedList = new LinkedList<>();
        }

        // 电压小于2000mV,即未装电池，当做空闲处理(没电芯就是空闲 待工艺是装上电芯)
        boolean isSl = null == vo || SettingConstant.SHELVE.equalsIgnoreCase(vo.getSetType()) || ServerConstant.START_FLAG_DISABLE == vo.getStartFlag();
        // 处理上送的异常数据
        if (isSl) {
            log.info("执行中的搁置周期数据 vo:{}", null == vo ? null : gson.toJson(vo));
            checkPutCache(key, current, voltage, false, Double.MAX_VALUE);
            return;
        }

        var oldStats = cachePutOrGet.getStatsCache(key);

        // 工步执行时间到状态修改为已完成
        if (null != oldStats) {
            double ts = oldStats.getTs();
            double time = vo.getExpectedTime() != null ? vo.getExpectedTime() * NumConstant.DOUBLE_SIXTY : 999999999999999D;
            if (ts >= time || Math.abs(ts - time) < NumConstant.DOUBLE_TEN) {
                oldStats.setIv(current, voltage);
                oldStats.setT(ErrorTypeEnum.EXECUTING.getCode());
                oldStats.setTs(Math.abs(ts - time) < NumConstant.DOUBLE_TEN ? time : ts);
                cachePutOrGet.putStatsCache(key, oldStats);
                // 已完成状态,修改操作记录状态
                log.info("已完成状态更新:{}-{}-{}-{}", ts, time, key, gson.toJson(vo));
                updateOperation(opKey, vo, true);
                return;
            }
        }


        // 正充电,负放电 查询是否有中断的容量缓存数据
        var interruptStats = cachePutOrGet.getInterruptStatsCache(key);
        boolean addInterrupt = null != interruptStats && (ServerConstant.START_FLAG_NORMAL == vo.getStartFlag() || ServerConstant.START_FLAG_FINISH == vo.getStartFlag());

        var stats = BatteryCapacityCalculator.calculateStats(commandSetType, oldStats, key, linkedList, current, voltage, cutOff);
        stats.setVo(vo);
        stats.setCty(commandSetType);

        // 中断执行中的
        //og.info("中断执行中的1:{}-{}-{}-{}", key, addInterrupt, null != firstDataCount && firstDataCount <= NumConstant.INT_FIVE, stats.getI() <= NumConstant.INT_FIFTY);
        if (addInterrupt && null != firstDataCount && firstDataCount <= NumConstant.INT_FIVE && stats.getI() > NumConstant.INT_ZERO && stats.getI() <= NumConstant.INT_FIFTY) {
            //log.info("中断执行中的0:{}-状态:{},时间:{}", key, stats.getT(), stats.getTs());
            stats.setT(ErrorTypeEnum.EXECUTING.getCode());
        }

        o.setS(stats);


        //if (vo.getCellNum() == 5) {
        //log.info("测试voltage:{},current:{},stats:{}", voltage, current, opKey);
        //}
        // 电池数据异常
        if (Math.abs(voltage) >= NumConstant.FLOAT_TWO_THOUSAND && ServerConstant.ERROR_EXCEPTION_TYPE_ERROR == stats.getEt()) {
            if (ServerConstant.START_FLAG_ERROR == vo.getStartFlag()) {
                //log.info("电池数据异常数据不处理opKey:{}", opKey);
                return;
            }
        }

        if (ServerConstant.ERROR_EXCEPTION_TYPE_NORMAL == stats.getEt() && ServerConstant.START_FLAG_NORMAL == vo.getStartFlag()) {
            cachePutOrGet.putCurrentCache(key, linkedList);
        }

        if (addInterrupt) {
            stats.setC(stats.getC() + interruptStats.getCap());
            stats.setTs(stats.getTs() + interruptStats.getTs());
            //log.info("容量中断数据:{}={}-{}-{}-{}", key, interruptStats.getCap(), interruptStats.getTs(), stats.getC(), stats.getTs());
        }
        cachePutOrGet.putStatsCache(key, stats);

        //  电池状态异常,停止状态更新
        if (Math.abs(voltage) >= NumConstant.FLOAT_TWO_THOUSAND && ServerConstant.ERROR_EXCEPTION_TYPE_ERROR == stats.getEt()) {
            log.info("电池状态异常,状态更新,ts:{},status:{},key:{}-{}", stats.getTs(), stats.getT(), key, o.getC());
            errorUpdateOperation(opKey, vo);
            return;
        }

        // 已完成状态,修改操作记录状态
        if (ErrorTypeEnum.EXECUTION_COMPLETED.getCode() == stats.getT()) {
            log.info("工步时间区间内首次符合已完成条件,状态更新,ts:{},status:{},key:{}", stats.getTs(), stats.getT(), key);
            updateOperation(opKey, vo, true);
        }
        updateOperation(opKey, vo, false);
    }

    private Integer getFirstDataCount(OperationVo vo, String key) {
        //log.info("测试getFirstDataCount:{}-{}", key, gson.toJson(vo));
        if (null != vo && null != vo.getOperationStartTime() && Math.abs(System.currentTimeMillis() - vo.getOperationStartTime()) < NumConstant.LONG_SIXTY * NumConstant.LONG_ONE_THOUSAND) {
            Integer firstDataCount = CaffeineUtil.get(CaffeineUtil.FIRST_DATA_LIST_KEY + key);
            if (null == firstDataCount) {
                firstDataCount = NumConstant.INT_ONE;
            } else {
                firstDataCount += NumConstant.INT_ONE;
            }

            if (firstDataCount <= NumConstant.INT_FIVE) {
                CaffeineUtil.set(CaffeineUtil.FIRST_DATA_LIST_KEY + key, firstDataCount, 40);
            }

            return firstDataCount;
        }
        return null;
    }

    private void updateOperation(String opKey, OperationVo vo, boolean finish) {
        if (null == vo) {
            return;
        }

        // 更新工步操作详情状态
        var detail = operationDetailMapper.findOneDetailByCellNum(vo.getCabinetNo(), vo.getBoardAddress(), vo.getCellNum());
        if (null != detail) {
            detail.setStartFlag(finish ? ServerConstant.START_FLAG_FINISH : ServerConstant.START_FLAG_NORMAL);
            detail.setUpdateTime(System.currentTimeMillis());
            operationDetailMapper.updateDetail(detail);
        }

        if (finish) {
            var jobTimes = new JobTimes();
            jobTimes.setOrderNo(vo.getOrderNo());
            jobTimes.setBoardNo(vo.getBoardAddress());
            jobTimes.setChannelNo(vo.getCellNum());
            jobTimes.setCabinetNo(Integer.parseInt(vo.getCabinetNo()));
            jobTimes.setInterruptOrEndStepId(vo.getStepId());
            jobTimes.setSingeType(vo.getSingleType());

            var cacheKey = KeyUtil.jobTimesKey(jobTimes);
            JobTimes finishJobTimes = CaffeineUtil.get(cacheKey);
            //log.info("未到结束次数删除定时任务cs:cacheKey:{}-{}-{}", cacheKey, finishJobTimes == null, vo);
            boolean isNotTimeOut = finishJobTimes != null && finishJobTimes.getTimeCount() - finishJobTimes.getTimes() > NumConstant.INT_ONE;

            if (isNotTimeOut) {
                var jobKey = CaffeineUtil.getCacheKey(Integer.parseInt(vo.getCabinetNo()), vo.getBoardAddress(), vo.getCellNum());
                // 停止定时任务
                var deleteJobName = JobConstant.JOB_NAME_COMMAND + CaffeineUtil.CACHE_KEY_SYMBOL + jobKey;
                R r = quartzService.deleteCronJob(deleteJobName);
                //log.info("未到结束次数删除定时任务 jobName：{} r:{}", deleteJobName, r);
                if (r == null || !ServerConstant.SUCCESS.equals(r.getCode())) {
                    log.info("未到结束次数删除定时任务失败 jobName：{} r:{}", deleteJobName, r);
                }


                int timeCount = finishJobTimes.getTimeCount();

                var interruptKey = Integer.parseInt(vo.getCabinetNo()) + CaffeineUtil.CACHE_KEY_SYMBOL + vo.getBoardAddress() + CaffeineUtil.CACHE_KEY_SYMBOL + vo.getCellNum();
                var interruptStats = cachePutOrGet.getInterruptStatsCache(interruptKey);
                int interruptCount = 0;
                if (null != interruptStats) {
                    interruptCount = interruptStats.getInterruptBeforeTimes();
                    //log.info("中断0统计：{}-time:{}-count:{}-ts:{}", interruptKey, interruptTime, interruptCount, interruptStats.ts);
                }

                int times = interruptCount + finishJobTimes.getTimes() + 1;
                // 完成，统计最后一笔数据
                log.info("完成,统计最后一笔数据：opKey:{},interruptCount:{}-{}-", opKey, interruptCount, gson.toJson(finishJobTimes));
                stepIssuedEventListenerQuartzJob.end(finishJobTimes, times, timeCount);
                // 增加一个最后的统计
            }

            // 更新缓存
            vo.setStartFlag(ServerConstant.START_FLAG_FINISH);
            CaffeineUtil.set(opKey, vo, 24 * 60 * 60);

            CaffeineUtil.delete(cacheKey);
        }
    }

    protected CapStatsVo checkPutCache(String key, int current, int voltage, boolean isIng, double time) {
        var stats = cachePutOrGet.getStatsCache(key);
        var interruptStats = cachePutOrGet.getInterruptStatsCache(key);
        if (stats == null) {
            stats = new CapStatsVo();
            stats.setTs(NumConstant.DOUBLE_ZERO);
        }

        stats.setAc(NumConstant.DOUBLE_ZERO);
        stats.setK(key);

        stats.setIv(Math.abs(current), Math.abs(voltage));
        // 终止状态 保留当前容量及时间数据,电池电压为电池实时数据
        if (ErrorTypeEnum.STOP.getCode() == stats.getT()) {
            stats.setCty(StepTypeNoEnum.STOP.getCode());
        } else {
            stats.setC(NumConstant.DOUBLE_ZERO);
        }

        var ts = stats.getTs();
        var isFinish = ts >= time;

        if (stats.getV() > NumConstant.INT_TWO_THOUSAND && ErrorTypeEnum.STOP.getCode() != stats.getT()) {
            stats.setTs(isIng && !isFinish ? stats.getTs() + NumConstant.DOUBLE_TEN : stats.getTs());
            stats.setT(isIng && !isFinish ? ErrorTypeEnum.EXECUTING.getCode() : ErrorTypeEnum.WAITING.getCode());
            stats.setCty(isIng ? StepTypeNoEnum.STEP_TYPE_SL_NUM.getCode() : StepTypeNoEnum.WAITING.getCode());
            if (isFinish) {
                stats.setT(ErrorTypeEnum.EXECUTION_COMPLETED.getCode());
            }
        }

        if (stats.getV() <= NumConstant.INT_TWO_THOUSAND) {
            stats.setT(ErrorTypeEnum.LEISURE.getCode());
            stats.setCty("");
        }

        //if (interruptStats != null) {
        if (interruptStats != null && isIng) {
            log.info("搁置或未进行工步有中断缓存数据key:{},time:{}-ts:{}", key, interruptStats.getInterruptBeforeTimes(), interruptStats.getTs());
            stats.setTs(stats.getTs() + interruptStats.getTs());
        }

        // 判断是否是异常数据
        int errorFlag = BatteryCapacityCalculator.errorData(Float.parseFloat(String.valueOf(current)), Float.parseFloat(String.valueOf(voltage)));
        if (ErrorTypeEnum.EXECUTING.getCode() != errorFlag) {
            stats.setT(errorFlag);
        }

        cachePutOrGet.putStatsCache(key, stats);

        return stats;
    }

    private void errorUpdateOperation(String opKey, OperationVo vo) {
        if (null == vo) {
            return;
        }

        // 更新工步操作详情状态
        var detail = operationDetailMapper.findOneDetailByCellNum(vo.getCabinetNo(), vo.getBoardAddress(), vo.getCellNum());
        if (null != detail && ServerConstant.START_FLAG_ERROR != detail.getStartFlag()) {
            log.info("更新工步操作详情状态为99异常状态:{}", gson.toJson(vo));
            detail.setStartFlag(ServerConstant.START_FLAG_ERROR);
            detail.setUpdateTime(System.currentTimeMillis());
            operationDetailMapper.updateDetail(detail);
        }

        var jobTimes = new JobTimes();
        jobTimes.setOrderNo(vo.getOrderNo());
        jobTimes.setChannelNo(vo.getCellNum());
        jobTimes.setBoardNo(vo.getBoardAddress());
        jobTimes.setSingeType(vo.getSingleType());
        jobTimes.setInterruptOrEndStepId(vo.getDetailsStepId());
        jobTimes.setCabinetNo(Integer.parseInt(vo.getCabinetNo()));

        var cacheKey = KeyUtil.jobTimesKey(jobTimes);
        JobTimes finishJobTimes = CaffeineUtil.get(cacheKey);
        if (null == finishJobTimes) {
            log.info("电池数据异常未找到定时任务 cacheKey:{},jobTimes:{}->vo:{}", cacheKey, gson.toJson(jobTimes), gson.toJson(vo));
            return;
        }

        var jobKey = CaffeineUtil.getCacheKey(Integer.parseInt(vo.getCabinetNo()), vo.getBoardAddress(), vo.getCellNum());
        // 停止定时任务
        var deleteJobName = JobConstant.JOB_NAME_COMMAND + CaffeineUtil.CACHE_KEY_SYMBOL + jobKey;
        R r = quartzService.deleteCronJob(deleteJobName);
        //log.info("未到结束次数删除定时任务 jobName：{} r:{}", deleteJobName, r);
        if (r == null || !ServerConstant.SUCCESS.equals(r.getCode())) {
            log.info("电池数据异常未到结束次数删除定时任务失败 jobName：{} r:{}", deleteJobName, r);
        }

//        int times = finishJobTimes.getTimes() + 1;
        int timeCount = finishJobTimes.getTimeCount();

        var interruptKey = Integer.parseInt(vo.getCabinetNo()) + CaffeineUtil.CACHE_KEY_SYMBOL + vo.getBoardAddress() + CaffeineUtil.CACHE_KEY_SYMBOL + vo.getCellNum();
        var interruptStats = cachePutOrGet.getInterruptStatsCache(interruptKey);
        int interruptCount = 0;
        if (null != interruptStats) {
            interruptCount = interruptStats.getInterruptBeforeTimes();
            //log.info("中断0统计：{}-time:{}-count:{}-ts:{}", interruptKey, interruptTime, interruptCount, interruptStats.ts);
        }

        int times = interruptCount + finishJobTimes.getTimes() + 1;

        // 完成，统计最后一笔数据
        log.info("电池数据异常,统计最后一笔数据：opKey:{}-{}", opKey, gson.toJson(finishJobTimes));
        stepIssuedEventListenerQuartzJob.end(finishJobTimes, times, timeCount);

        // 更新缓存
        vo.setStartFlag(ServerConstant.START_FLAG_ERROR);
        CaffeineUtil.set(opKey, vo, 24 * 60 * 60);

        CaffeineUtil.delete(cacheKey);
    }

    private void oneBatteryCache(OperationVo vo, CapStatsVo s, int cabinetNo, int boardNo, int channelNo) {
        var key = cabinetNo + CaffeineUtil.CACHE_KEY_SYMBOL + boardNo + CaffeineUtil.CACHE_KEY_SYMBOL + channelNo;
        var cacheKey = CaffeineUtil.R_CAP_STATS_VO_KEY + key;
        if (null == vo || null == s) {
            var svo = null != s && s.getV() > NumConstant.INT_TWO_THOUSAND ? s : getEmptyStats(key);
            // 缓存数据
            CaffeineUtil.set(cacheKey, svo, 20);
            return;
        }

        s.setIv(Math.abs(s.getI()), Math.abs(s.getV()));

        // 异常状态
        if (ServerConstant.START_FLAG_ERROR == vo.getStartFlag()) {
            s = s.getV() > NumConstant.INT_TWO_THOUSAND ? s : getEmptyStats(key);
            // 缓存数据
            CaffeineUtil.set(cacheKey, s, 20);
            return;
        }

        // 已完成的通道查询放电数据，放电数据没有已当前的缓存数据
        if (ServerConstant.START_FLAG_FINISH == vo.getStartFlag()) {
            // 查询已经放电完成数据的统计数据
            s = CaffeineUtil.get(cacheKey);
            if (null == s) {
                s = disChargeStats(cabinetNo, boardNo, channelNo, vo.getOperationId(), key, s);
            }
            // 缓存数据
            CaffeineUtil.set(cacheKey, s, 20);
            return;
        }

        // 终止状态 保留当前容量及时间数据,电池电压为电池实时数据
        if (ServerConstant.START_FLAG_DISABLE == vo.getStartFlag()) {
            CapStatsVo cvo = null;

            if (s.getV() > NumConstant.INT_TWO_THOUSAND
                    && s.getV() != (int) NumConstant.FLOAT_PWM_ERROR
                    && s.getV() != (int) NumConstant.FLOAT_CHECK_ERROR
                    && s.getV() != (int) NumConstant.FLOAT_BATTERY_LIMIT) {
                s.setT(ErrorTypeEnum.STOP.getCode());
                s.setCty(StepTypeNoEnum.STOP.getCode());

                // 查询有没有放电数据
                cvo = CaffeineUtil.get(cacheKey);
                if (null == cvo) {
                    cvo = disChargeStatsStop(cabinetNo, boardNo, channelNo, vo.getOperationId(), key, s);
                    if (null != cvo) {
                        cvo.setT(ErrorTypeEnum.STOP.getCode());
                    }
                }
            }

            s = null != cvo ? cvo : s;
            // 缓存数据
            CaffeineUtil.set(cacheKey, s, 20);
            return;
        }

        // 进行中状态
        if (ServerConstant.START_FLAG_NORMAL == vo.getStartFlag()) {
            if (s.getV() > NumConstant.INT_TWO_THOUSAND
                    && s.getT() != ErrorTypeEnum.EXECUTING.getCode()
                    && s.getV() != (int) NumConstant.FLOAT_PWM_ERROR
                    && s.getV() != (int) NumConstant.FLOAT_CHECK_ERROR
                    && s.getV() != (int) NumConstant.FLOAT_BATTERY_LIMIT) {
                s.setT(ErrorTypeEnum.EXECUTING.getCode());
            }
        }

        // todo 缓存
        // 缓存数据
        CaffeineUtil.set(CaffeineUtil.R_CAP_STATS_VO_KEY, s, 20);
    }

    private CapStatsVo getEmptyStats(String key) {
        var stats = new CapStatsVo();
        stats.setIv(NumConstant.INT_ZERO, NumConstant.INT_ZERO);
        stats.setC(NumConstant.DOUBLE_ZERO);
        stats.setTs(NumConstant.DOUBLE_ZERO);
        stats.setAc(NumConstant.DOUBLE_ZERO);
        stats.setK(key);
        stats.setCty("");
        stats.setT(ErrorTypeEnum.LEISURE.getCode());

        return stats;
    }

    /**
     * 放电容量数据
     */
    private CapStatsVo disChargeStatsStop(int cabinetNo, int boardNo, int channelNo, String operationId, String key, CapStatsVo s) {
        var sdo = tableMapper.queryStatsDoLast(TableConstant.TABLE_REAL_TIME_STATS, Integer.parseInt("" + cabinetNo), operationId, boardNo, channelNo);
        return null != sdo && null != sdo.getData() ? hasStatsDataVo(sdo, key, s) : null;
    }

    /**
     * 放电容量数据
     */
    private CapStatsVo disChargeStats(int cabinetNo, int boardNo, int channelNo, String operationId, String key, CapStatsVo s) {
        var sdo = tableMapper.queryStatsDoLast(TableConstant.TABLE_REAL_TIME_STATS, Integer.parseInt("" + cabinetNo), operationId, boardNo, channelNo);
        if (null != sdo && null != sdo.getData()) {
            return hasStatsData(sdo, key, s);
        }

        // 没有放电结束的统计数据,而且不是异常数字
        if (null != s && s.getV() > NumConstant.INT_TWO_THOUSAND
                && s.getV() != (int) NumConstant.FLOAT_PWM_ERROR
                && s.getV() != (int) NumConstant.FLOAT_CHECK_ERROR
                && s.getV() != (int) NumConstant.FLOAT_BATTERY_LIMIT) {
            s.setT(ErrorTypeEnum.EXECUTION_COMPLETED.getCode());
        }

        return null != s ? s : getEmptyStats(key);
    }

    private CapStatsVo hasStatsData(StatsDo sdo, String key, CapStatsVo s) {
        byte[] data;
        try {
            data = compressionService.decompress(sdo.getData());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        var v = gson.fromJson(new String(data, StandardCharsets.UTF_8), RealTimeVo.class);
        // 没数据
        if (v == null) {
            return null;
        }

        var stats = new CapStatsVo();
        stats.setK(key);
        stats.setIv(Math.abs(s.getI()), Math.abs(s.getV()));

        stats.setT(v.getT());
        stats.setCty(v.getCty());

        stats.setC(v.getCpa());
        stats.setAc(v.getAc());
        //stats.setTs(v.getTs());
        // 完成时间去同时总时间
        stats.setTs(null != sdo.getTime() ? sdo.getTime().doubleValue() : v.getTs());
        return stats;
    }


    private CapStatsVo hasStatsDataVo(StatsDo sdo, String key, CapStatsVo s) {
        byte[] data;
        try {
            data = compressionService.decompress(sdo.getData());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        var v = gson.fromJson(new String(data, StandardCharsets.UTF_8), RealTimeVo.class);
        // 没数据
        if (null == v) {
            return null;
        }

        var stats = new CapStatsVo();
        stats.setK(key);
        stats.setIv(Math.abs(s.getI()), Math.abs(s.getV()));

        stats.setT(v.getT());
        stats.setCty(v.getCty());

        stats.setC(v.getCpa());
        stats.setAc(v.getAc());
        //stats.setTs(v.getTs());
        // 完成时间去同时总时间
        stats.setTs(null != sdo.getTime() ? sdo.getTime().doubleValue() : v.getTs());

        return stats;
    }

}
